#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>

#include <net/if.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>

int sockfd;

void sighandler(int sig)
{
    // 4，静静地等待对方的消息
    char buf[100];
    struct sockaddr_in peeraddr;
    socklen_t len = sizeof(peeraddr);
    bzero(buf, 100);
    bzero(&peeraddr, sizeof(peeraddr));

    int ret = recvfrom(sockfd, buf, 100, 0,
                        (struct sockaddr *)&peeraddr, &len);

    if(ret == -1)
    {
        perror("recvfrom() faield");
        exit(0);
    }

    printf("收到[%s:%hu]的消息：%s",
            inet_ntoa(peeraddr.sin_addr),
            ntohs(peeraddr.sin_port),
            buf);
}

int main(int argc, char const *argv[])
{
    if(argc != 3)
    {
        printf("请指定绑定的网卡名称和端口\n");
        exit(0);
    }

    // 1，创建UDP通信端点
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd > 0)
        printf("创建socket成功\n");


    // 从指定网卡获取其IP地址
    struct ifreq ifr;
    strcpy(ifr.ifr_ifrn.ifrn_name, argv[1]);

    // 获取指定网口IP地址
    ioctl(sockfd, SIOCGIFADDR, &ifr);


    // 2，准备好自己的地址结构体
    struct sockaddr_in myaddr;
    bzero(&myaddr, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 自动获取本机IP
    // myaddr.sin_addr = ((struct sockaddr_in *)&(ifr.ifr_ifru.ifru_broadaddr))->sin_addr;
    myaddr.sin_port = htons(atoi(argv[2]));

    // 3，绑定套接字与地址
    if(bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) == 0)
        printf("bind() 成功\n");


    // a. 注册信号SIGIO的处理响应函数
    signal(SIGIO, sighandler);

    // b. 设置SIGIO信号的属主
    fcntl(sockfd, F_SETOWN, getpid()); // SIGIO ==> 本进程

    // c. 手工使能系统产生信号SIGIO
    long state = fcntl(sockfd, F_GETFL);
    state |= O_ASYNC;
    fcntl(sockfd, F_SETFL, state);


    // 主线程继续做其他事情...
    for(int i=0;;i++,i%=26)
    {
        fprintf(stderr, "%c", 'a'+i);
        usleep(200*1000);
    }

    return 0;
}
